//! Control flow statement parsing (if, return, break, continue)

use super::super::{parse_expression, Parser};
use super::blocks::parse_block_statement;
use crate::ast::expr::{Expression, MethodCallExpr, Pattern};
use crate::ast::stmt::{
    BlockStmt, BreakStmt, ContinueStmt, IfStmt, ReturnStmt, Statement, VariableDeclStmt,
};
use crate::error::{CompilerError, Location, Result};
use crate::lexer::token::Token;
use crate::parser::expr_parser::parse_pattern_or;

/// Parse if statement (Go-style)
pub fn parse_if_statement(parser: &mut Parser) -> Result<IfStmt> {
    parser.expect(&Token::If)?;

    // Parse condition (without parentheses, Go-style)
    let condition = parse_expression(parser)?;
    if condition.is_none() {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected condition after 'if'",
        ));
    }

    // Require opening brace (Go-style)
    if !parser.check(&Token::LeftBrace) {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected '{' after if condition (Go-style syntax)",
        ));
    }

    // Parse then block
    let then_branch = parse_block_statement(parser)?;

    // Parse else/else if
    let else_branch = if parser.consume(&Token::Else)? {
        if parser.check(&Token::If) {
            let is_if_var = matches!(
                parser.peek_ahead(1).map(|t| &t.token),
                Some(Token::Var)
            );
            if is_if_var {
                let stmt = parse_if_var_statement(parser)?;
                Some(Box::new(stmt))
            } else {
                let nested_if = parse_if_statement(parser)?;
                Some(Box::new(Statement::If(nested_if)))
            }
        } else if parser.check(&Token::LeftBrace) {
            // else: parse block
            let else_block = parse_block_statement(parser)?;
            Some(Box::new(Statement::Block(else_block)))
        } else {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                "Expected '{' or 'if' after 'else'",
            ));
        }
    } else {
        None
    };

    Ok(IfStmt {
        condition: condition.unwrap(),
        then_branch: Box::new(Statement::Block(then_branch)),
        else_branch,
        location: parser.current_location(),
    })
}

/// Parse `if var Pattern = expr { ... }` and desugar into regular statements
pub fn parse_if_var_statement(parser: &mut Parser) -> Result<Statement> {
    let if_location = parser.current_location();
    parser.expect(&Token::If)?;
    parser.expect(&Token::Var)?;

    let pattern = parse_pattern_or(parser)?.ok_or_else(|| {
        CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected pattern after 'if var'",
        )
    })?;

    parser.expect(&Token::Assign)?;

    let match_expr = parse_expression(parser)?.ok_or_else(|| {
        CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected expression after '=' in 'if var' statement",
        )
    })?;

    if !parser.check(&Token::LeftBrace) {
        return Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected '{' after 'if var' condition",
        ));
    }

    let then_block = parse_block_statement(parser)?;

    let else_branch = if parser.consume(&Token::Else)? {
        if parser.check(&Token::If) {
            let is_if_var = matches!(
                parser.peek_ahead(1).map(|t| &t.token),
                Some(Token::Var)
            );
            if is_if_var {
                Some(parse_if_var_statement(parser)?)
            } else {
                Some(Statement::If(parse_if_statement(parser)?))
            }
        } else if parser.check(&Token::LeftBrace) {
            Some(Statement::Block(parse_block_statement(parser)?))
        } else {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                "Expected '{' or 'if' after 'else'",
            ));
        }
    } else {
        None
    };

    desugar_if_var_statement(
        parser,
        pattern,
        match_expr,
        then_block,
        else_branch,
        if_location,
    )
}

/// Parse return statement
pub fn parse_return_statement(parser: &mut Parser) -> Result<ReturnStmt> {
    parser.expect(&Token::Return)?;

    // 检查return后面是否有返回值
    // 如果后面是分号、换行符、右大括号，或者是新的语句关键字，则没有返回值
    let value = if parser.check(&Token::Semicolon)
        || parser.check(&Token::RightBrace)
        || parser.is_at_end()
        || matches!(
            parser.peek().map(|t| &t.token),
            Some(Token::Var)
                | Some(Token::If)
                | Some(Token::For)
                | Some(Token::While)
                | Some(Token::Return)
                | Some(Token::Break)
                | Some(Token::Continue)
                | Some(Token::Defer)
                | Some(Token::Match)
        ) {
        None
    } else {
        parse_expression(parser)?
    };

    // 可选的分号，支持无分号语法
    parser.consume(&Token::Semicolon).ok();

    Ok(ReturnStmt {
        value,
        location: parser.current_location(),
    })
}

/// Parse break statement
pub fn parse_break_statement(parser: &mut Parser) -> Result<BreakStmt> {
    parser.expect(&Token::Break)?;

    let label = if let Some(Token::Identifier(label_name)) = parser.peek().map(|t| &t.token) {
        let label = label_name.clone();
        parser.advance()?;
        Some(label)
    } else {
        None
    };

    parser.expect(&Token::Semicolon)?;

    Ok(BreakStmt {
        label,
        location: parser.current_location(),
    })
}

/// Parse continue statement
pub fn parse_continue_statement(parser: &mut Parser) -> Result<ContinueStmt> {
    parser.expect(&Token::Continue)?;

    let label = if let Some(Token::Identifier(label_name)) = parser.peek().map(|t| &t.token) {
        let label = label_name.clone();
        parser.advance()?;
        Some(label)
    } else {
        None
    };

    parser.expect(&Token::Semicolon)?;

    Ok(ContinueStmt {
        label,
        location: parser.current_location(),
    })
}

fn desugar_if_var_statement(
    parser: &mut Parser,
    pattern: Pattern,
    match_expr: Expression,
    mut then_block: BlockStmt,
    else_branch: Option<Statement>,
    location: Location,
) -> Result<Statement> {
    let temp_name = parser.next_temp_name("ifvar_tmp");
    let plan = analyze_if_var_pattern(&pattern, location)?;

    let temp_decl = Statement::VariableDecl(VariableDeclStmt {
        name: temp_name.clone(),
        var_type: None,
        initializer: Some(match_expr),
        mutable: true,
        location,
    });

    if let Some(binding) = &plan.binding {
        if let Some(var_name) = &binding.variable_name {
            let binding_expr = make_method_call(&temp_name, binding.method, location);
            let binding_stmt = Statement::VariableDecl(VariableDeclStmt {
                name: var_name.clone(),
                var_type: None,
                initializer: Some(binding_expr),
                mutable: true,
                location,
            });

            let mut statements = Vec::new();
            statements.push(binding_stmt);
            statements.extend(then_block.statements);
            then_block.statements = statements;
        }
    }

    let condition_expr = make_method_call(&temp_name, plan.condition_method, location);

    let if_stmt = Statement::If(IfStmt {
        condition: condition_expr,
        then_branch: Box::new(Statement::Block(then_block)),
        else_branch: else_branch.map(Box::new),
        location,
    });

    Ok(Statement::Block(BlockStmt {
        statements: vec![temp_decl, if_stmt],
        location,
    }))
}

struct IfVarPlan {
    condition_method: &'static str,
    binding: Option<IfVarBinding>,
}

struct IfVarBinding {
    variable_name: Option<String>,
    method: &'static str,
}

fn analyze_if_var_pattern(pattern: &Pattern, location: Location) -> Result<IfVarPlan> {
    let enum_pattern = match pattern {
        Pattern::Enum(enum_pattern) => enum_pattern,
        _ => {
            return Err(CompilerError::syntax(
                location.line,
                location.column,
                "`if var` only supports Option/Result enum patterns",
            ))
        }
    };

    let (condition_method, binding_method, expected_fields) = match (
        enum_pattern.enum_name.as_str(),
        enum_pattern.variant_name.as_str(),
    ) {
        ("Option", "Some") => ("is_some", Some("unwrap"), 1),
        ("Option", "None") => ("is_none", None, 0),
        ("Result", "Ok") => ("is_ok", Some("unwrap"), 1),
        ("Result", "Err") => ("is_err", Some("unwrap_err"), 1),
        _ => {
            return Err(CompilerError::syntax(
                location.line,
                location.column,
                "`if var` only supports Option::Some/None and Result::Ok/Err patterns",
            ))
        }
    };

    if enum_pattern.patterns.len() > expected_fields {
        return Err(CompilerError::syntax(
            location.line,
            location.column,
            "Pattern has too many fields for this variant",
        ));
    }

    let binding_name = if expected_fields == 0 {
        None
    } else {
        match enum_pattern.patterns.get(0) {
            Some(Pattern::Variable(name)) => Some(name.clone()),
            Some(Pattern::Wildcard) | None => None,
            _ => {
                return Err(CompilerError::syntax(
                    location.line,
                    location.column,
                    "Only single variable or '_' is supported inside the pattern",
                ))
            }
        }
    };

    let binding = binding_method.map(|method| IfVarBinding {
        variable_name: binding_name,
        method,
    });

    Ok(IfVarPlan {
        condition_method,
        binding,
    })
}

fn make_method_call(temp_name: &str, method: &str, location: Location) -> Expression {
    Expression::MethodCall(MethodCallExpr {
        object: Box::new(Expression::Variable(temp_name.to_string())),
        method: method.to_string(),
        type_args: Vec::new(),
        arguments: Vec::new(),
        location,
    })
}
